import { AssetManager, assetManager } from 'cc';
import { resLoader } from './resload';
import { Log } from '../logger/LoggerGlobal';

/**
 * 资源包配置接口
 */
export interface IBundleConfig {
    /** 资源包名称 */
    name: string;
    /** 资源包版本号 */
    version?: string;
    /** 资源包远程URL（可选） */
    url?: string;
    /** 是否为远程资源包 */
    isRemote?: boolean;
    /** 资源包优先级（数字越大优先级越高） */
    priority?: number;
    /** 是否自动加载 */
    autoLoad?: boolean;
    /** 依赖的其他资源包 */
    dependencies?: string[];
    /** 额外配置参数 */
    options?: { [key: string]: any };
}

/**
 * 资源包状态
 */
export enum BundleState {
    /** 未加载 */
    Unloaded = 0,
    /** 加载中 */
    Loading = 1,
    /** 已加载 */
    Loaded = 2,
    /** 加载失败 */
    Failed = 3,
}

/**
 * 资源包信息
 */
export interface IBundleInfo {
    /** 配置信息 */
    config: IBundleConfig;
    /** 资源包实例 */
    bundle: AssetManager.Bundle | null;
    /** 当前状态 */
    state: BundleState;
    /** 加载时间 */
    loadTime?: number;
    /** 资源包大小（字节） */
    size?: number;
    /** 引用计数 */
    refCount: number;
    /** 最后访问时间 */
    lastAccessTime: number;
}

/**
 * 资源包加载进度回调
 */
export type BundleProgressCallback = (bundleName: string, progress: number) => void;

/**
 * 资源包加载完成回调
 */
export type BundleCompleteCallback = (bundleName: string, bundle: AssetManager.Bundle | null, error?: Error) => void;

/**
 * 资源包管理器
 * 
 * 功能特性：
 * - 资源包生命周期管理（加载、卸载、释放）
 * - 资源包版本控制
 * - 资源包依赖管理
 * - 资源包缓存策略
 * - 资源包热更新支持
 * - 完整的统计和监控
 * - 集成节点池管理器
 */
export class BundleManager {
    private static _instance: BundleManager;

    /** 资源包信息映射表 */
    private readonly bundleInfos: Map<string, IBundleInfo> = new Map();

    /** 正在加载的资源包 */
    private readonly loadingBundles: Set<string> = new Set();

    /** 资源包配置注册表 */
    private readonly bundleConfigs: Map<string, IBundleConfig> = new Map();

    /** 全局加载进度回调 */
    private globalProgressCallback: BundleProgressCallback | null = null;

    /** 全局加载完成回调 */
    private globalCompleteCallback: BundleCompleteCallback | null = null;

    /** 最大缓存资源包数量 */
    private maxCachedBundles: number = 10;

    /** 是否启用自动卸载 */
    private enableAutoUnload: boolean = true;

    /** 自动卸载超时时间（毫秒），默认5分钟 */
    private autoUnloadTimeout: number = 5 * 60 * 1000;

    private constructor() {
        this.initDefaultBundles();
    }

    /**
     * 获取单例实例
     */
    public static getInstance(): BundleManager {
        if (!BundleManager._instance) {
            BundleManager._instance = new BundleManager();
        }
        return BundleManager._instance;
    }

    /**
     * 初始化默认资源包
     */
    private initDefaultBundles() {
        // 注册默认 resources 资源包
        this.registerBundle({
            name: 'resources',
            priority: 999,
            autoLoad: true,
        });

        // 注册默认 internal 资源包
        this.registerBundle({
            name: 'internal',
            priority: 1000,
            autoLoad: true,
        });
    }

    /**
     * 注册资源包配置
     * @param config 资源包配置
     */
    public registerBundle(config: IBundleConfig): void {
        if (!config.name) {
            throw new Error('资源包名称不能为空');
        }

        // 合并默认配置
        const fullConfig: IBundleConfig = {
            priority: 0,
            autoLoad: false,
            isRemote: false,
            dependencies: [],
            ...config,
        };

        this.bundleConfigs.set(config.name, fullConfig);

        Log.resource.info('注册资源包', { name: config.name });
    }

    /**
     * 批量注册资源包
     * @param configs 资源包配置数组
     */
    public registerBundles(configs: IBundleConfig[]): void {
        configs.forEach(config => this.registerBundle(config));
    }

    /**
     * 加载资源包
     * @param bundleName 资源包名称
     * @param onProgress 进度回调
     * @param onComplete 完成回调
     */
    public async loadBundle(
        bundleName: string,
        onProgress?: BundleProgressCallback,
        onComplete?: BundleCompleteCallback
    ): Promise<AssetManager.Bundle | null> {
        // 检查是否已加载
        const info = this.bundleInfos.get(bundleName);
        if (info && info.state === BundleState.Loaded && info.bundle) {
            info.refCount++;
            info.lastAccessTime = Date.now();
            if (onComplete) {
                onComplete(bundleName, info.bundle);
            }
            return info.bundle;
        }

        // 检查是否正在加载
        if (this.loadingBundles.has(bundleName)) {
            Log.resource.warn('资源包正在加载中', { bundleName });
            return null;
        }

        // 获取配置
        const config = this.bundleConfigs.get(bundleName) || { name: bundleName };

        // 加载依赖
        if (config.dependencies && config.dependencies.length > 0) {
            await this.loadDependencies(config.dependencies);
        }

        // 标记为加载中
        this.loadingBundles.add(bundleName);

        // 更新或创建资源包信息
        const bundleInfo: IBundleInfo = info || {
            config,
            bundle: null,
            state: BundleState.Loading,
            refCount: 0,
            lastAccessTime: Date.now(),
        };

        bundleInfo.state = BundleState.Loading;
        this.bundleInfos.set(bundleName, bundleInfo);

        const startTime = Date.now();

        try {
            // 使用 resLoader 加载资源包
            const options = config.version ? { version: config.version, ...config.options } : config.options;
            const bundle = await resLoader.loadBundle(bundleName, options);

            if (bundle) {
                bundleInfo.bundle = bundle;
                bundleInfo.state = BundleState.Loaded;
                bundleInfo.loadTime = Date.now() - startTime;
                bundleInfo.refCount++;
                bundleInfo.lastAccessTime = Date.now();

                Log.resource.info('资源包加载成功', {
                    bundleName,
                    loadTime: `${bundleInfo.loadTime}ms`
                });

                // 触发回调
                if (onProgress) {
                    onProgress(bundleName, 1);
                }
                if (this.globalProgressCallback) {
                    this.globalProgressCallback(bundleName, 1);
                }
                if (onComplete) {
                    onComplete(bundleName, bundle);
                }
                if (this.globalCompleteCallback) {
                    this.globalCompleteCallback(bundleName, bundle);
                }

                return bundle;
            } else {
                throw new Error(`加载资源包 ${bundleName} 失败`);
            }
        } catch (error) {
            bundleInfo.state = BundleState.Failed;
            Log.resource.error('资源包加载失败', {
                bundleName,
                error
            });

            if (onComplete) {
                onComplete(bundleName, null, error as Error);
            }
            if (this.globalCompleteCallback) {
                this.globalCompleteCallback(bundleName, null, error as Error);
            }

            return null;
        } finally {
            this.loadingBundles.delete(bundleName);
        }
    }

    /**
     * 批量加载资源包
     * @param bundleNames 资源包名称数组
     * @param onProgress 进度回调
     */
    public async loadBundles(
        bundleNames: string[],
        onProgress?: (loaded: number, total: number) => void
    ): Promise<Map<string, AssetManager.Bundle | null>> {
        const results = new Map<string, AssetManager.Bundle | null>();
        const total = bundleNames.length;
        let loaded = 0;

        // 按优先级排序
        const sortedNames = this.sortBundlesByPriority(bundleNames);

        for (const name of sortedNames) {
            const bundle = await this.loadBundle(name);
            results.set(name, bundle);
            loaded++;

            if (onProgress) {
                onProgress(loaded, total);
            }
        }

        return results;
    }

    /**
     * 加载依赖资源包
     * @param dependencies 依赖资源包名称数组
     */
    private async loadDependencies(dependencies: string[]): Promise<void> {
        const promises = dependencies.map(dep => this.loadBundle(dep));
        await Promise.all(promises);
    }

    /**
     * 按优先级排序资源包
     * @param bundleNames 资源包名称数组
     */
    private sortBundlesByPriority(bundleNames: string[]): string[] {
        return bundleNames.sort((a, b) => {
            const configA = this.bundleConfigs.get(a);
            const configB = this.bundleConfigs.get(b);
            const priorityA = configA?.priority || 0;
            const priorityB = configB?.priority || 0;
            return priorityB - priorityA;
        });
    }

    /**
     * 获取资源包
     * @param bundleName 资源包名称
     */
    public getBundle(bundleName: string): AssetManager.Bundle | null {
        const info = this.bundleInfos.get(bundleName);
        if (info && info.bundle) {
            info.lastAccessTime = Date.now();
            return info.bundle;
        }

        // 尝试从引擎获取
        const bundle = resLoader.getBundle(bundleName);
        if (bundle) {
            // 更新本地记录
            this.bundleInfos.set(bundleName, {
                config: this.bundleConfigs.get(bundleName) || { name: bundleName },
                bundle,
                state: BundleState.Loaded,
                refCount: 1,
                lastAccessTime: Date.now(),
            });
            return bundle;
        }
        return null;
    }

    /**
     * 检查资源包是否已加载
     * @param bundleName 资源包名称
     */
    public hasBundle(bundleName: string): boolean {
        const info = this.bundleInfos.get(bundleName);
        return info ? info.state === BundleState.Loaded && info.bundle !== null : false;
    }

    /**
     * 获取资源包状态
     * @param bundleName 资源包名称
     */
    public getBundleState(bundleName: string): BundleState {
        const info = this.bundleInfos.get(bundleName);
        return info ? info.state : BundleState.Unloaded;
    }

    /**
     * 增加资源包引用计数
     * @param bundleName 资源包名称
     */
    public retainBundle(bundleName: string): void {
        const info = this.bundleInfos.get(bundleName);
        if (info) {
            info.refCount++;
            info.lastAccessTime = Date.now();
        }
    }

    /**
     * 减少资源包引用计数
     * @param bundleName 资源包名称
     * @param autoUnload 是否自动卸载（当引用为0时）
     */
    public releaseBundle(bundleName: string, autoUnload: boolean = false): void {
        const info = this.bundleInfos.get(bundleName);
        if (info) {
            info.refCount = Math.max(0, info.refCount - 1);
            
            if (autoUnload && info.refCount === 0) {
                this.scheduleUnload(bundleName);
            }
        }
    }

    /**
     * 计划卸载资源包
     * @param bundleName 资源包名称
     */
    private scheduleUnload(bundleName: string): void {
        if (!this.enableAutoUnload) {
            return;
        }

        setTimeout(() => {
            const info = this.bundleInfos.get(bundleName);
            if (info && info.refCount === 0) {
                this.unloadBundle(bundleName);
            }
        }, this.autoUnloadTimeout);
    }

    /**
     * 卸载资源包
     * @param bundleName 资源包名称
     * @param force 是否强制卸载（忽略引用计数）
     */
    public unloadBundle(bundleName: string, force: boolean = false): void {
        const info = this.bundleInfos.get(bundleName);
        if (!info) {
            Log.resource.warn('资源包不存在', { bundleName });
            return;
        }

        if (!force && info.refCount > 0) {
            Log.resource.warn('资源包仍有引用，无法卸载', {
                bundleName,
                refCount: info.refCount
            });
            return;
        }

        if (info.bundle) {
            // 使用 resLoader 卸载资源包
            resLoader.removeBundle(bundleName);
            Log.resource.info('资源包已卸载', { bundleName });
        }

        // 更新状态
        info.bundle = null;
        info.state = BundleState.Unloaded;
        info.refCount = 0;
    }

    /**
     * 卸载所有资源包（除了默认资源包）
     */
    public unloadAllBundles(excludeDefault: boolean = true): void {
        const bundleNames = Array.from(this.bundleInfos.keys());
        
        for (const name of bundleNames) {
            // 跳过默认资源包
            if (excludeDefault && (name === 'resources' || name === 'internal')) {
                continue;
            }

            this.unloadBundle(name, true);
        }

        Log.resource.info('所有资源包已卸载');
    }

    /**
     * 清理未使用的资源包（引用计数为0）
     */
    public cleanupUnusedBundles(): number {
        let count = 0;
        const now = Date.now();

        this.bundleInfos.forEach((info, name) => {
            if (info.refCount === 0 && 
                info.state === BundleState.Loaded && 
                (now - info.lastAccessTime) > this.autoUnloadTimeout) {
                this.unloadBundle(name);
                count++;
            }
        });

        if (count > 0) {
            Log.resource.info('清理未使用的资源包', { count });
        }

        return count;
    }

    /**
     * 获取所有已加载的资源包名称
     */
    public getLoadedBundleNames(): string[] {
        const names: string[] = [];
        this.bundleInfos.forEach((info, name) => {
            if (info.state === BundleState.Loaded && info.bundle) {
                names.push(name);
            }
        });
        return names;
    }

    /**
     * 获取资源包信息
     * @param bundleName 资源包名称
     */
    public getBundleInfo(bundleName: string): IBundleInfo | null {
        return this.bundleInfos.get(bundleName) || null;
    }

    /**
     * 获取所有资源包信息
     */
    public getAllBundleInfos(): Map<string, IBundleInfo> {
        return new Map(this.bundleInfos);
    }

    /**
     * 设置全局进度回调
     * @param callback 回调函数
     */
    public setGlobalProgressCallback(callback: BundleProgressCallback | null): void {
        this.globalProgressCallback = callback;
    }

    /**
     * 设置全局完成回调
     * @param callback 回调函数
     */
    public setGlobalCompleteCallback(callback: BundleCompleteCallback | null): void {
        this.globalCompleteCallback = callback;
    }

    /**
     * 设置最大缓存资源包数量
     * @param count 数量
     */
    public setMaxCachedBundles(count: number): void {
        this.maxCachedBundles = Math.max(1, count);
    }

    /**
     * 设置是否启用自动卸载
     * @param enable 是否启用
     */
    public setEnableAutoUnload(enable: boolean): void {
        this.enableAutoUnload = enable;
    }

    /**
     * 设置自动卸载超时时间
     * @param timeout 超时时间（毫秒）
     */
    public setAutoUnloadTimeout(timeout: number): void {
        this.autoUnloadTimeout = Math.max(0, timeout);
    }

    /**
     * 打印所有资源包信息（调试用）
     */
    public printBundleInfos(): void {
        Log.performance.info('======== 资源包信息 ========');
        this.bundleInfos.forEach((info, name) => {
            const stateStr = ['未加载', '加载中', '已加载', '失败'][info.state];
            Log.performance.info(`[${name}]`, {
                '状态': stateStr,
                '引用计数': info.refCount,
                '加载耗时': info.loadTime ? `${info.loadTime}ms` : 'N/A',
                '优先级': info.config.priority || 0,
                '版本': info.config.version || 'N/A',
                '最后访问': new Date(info.lastAccessTime).toLocaleString(),
            });
        });
        Log.performance.info('===========================');
    }

    /**
     * 获取统计信息
     */
    public getStatistics(): {
        total: number;
        loaded: number;
        loading: number;
        failed: number;
        totalRefCount: number;
    } {
        let total = 0;
        let loaded = 0;
        let loading = 0;
        let failed = 0;
        let totalRefCount = 0;

        this.bundleInfos.forEach(info => {
            total++;
            totalRefCount += info.refCount;

            switch (info.state) {
                case BundleState.Loaded:
                    loaded++;
                    break;
                case BundleState.Loading:
                    loading++;
                    break;
                case BundleState.Failed:
                    failed++;
                    break;
            }
        });

        return {
            total,
            loaded,
            loading,
            failed,
            totalRefCount,
        };
    }

    /**
     * 预加载资源包列表（用于游戏启动时）
     * @param bundleNames 资源包名称数组
     */
    public async preloadBundles(bundleNames: string[]): Promise<void> {
        Log.resource.info('开始预加载资源包', { count: bundleNames.length });
        
        const startTime = Date.now();
        await this.loadBundles(bundleNames, (loaded, total) => {
            const progress = ((loaded / total) * 100).toFixed(2);
            Log.resource.debug('预加载进度', {
                progress: `${progress}%`,
                loaded,
                total
            });
        });

        const totalTime = Date.now() - startTime;
        Log.resource.info('预加载完成', { totalTime: `${totalTime}ms` });
    }
}

/**
 * 导出单例实例
 */
export const bundleManager = BundleManager.getInstance();
